import string
import time
from typing import Union

from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.relative_locator import locate_with, RelativeBy
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BasePage:
    def __init__(self,driver):
        self.driver= driver
        self.driver.maximize_window()
    def goto_page(self,url):
        self.driver.get(url)
    def find_elements(self,locator):
        if isinstance(locator, RelativeBy):
            return self.driver.find_elements(locator)
        return self.driver.find_elements(*locator)

    def find_element(self,locator:Union[tuple,RelativeBy])->WebElement:
        '''
        :param locator:
        :return:
        '''
        if isinstance(locator,RelativeBy):
            return self.driver.find_element(locator)
        return self.driver.find_element(*locator)

    def element_right_of(self,dst_locator:tuple,ref_locator:tuple)->WebElement:
        '''
        :param locator:
        :return:
        '''
        locator = locate_with(*dst_locator).to_right_of({ref_locator[0]:ref_locator[1]})
        return locator
    def element_left_of(self,dst_locator:tuple,ref_locator:tuple)->WebElement:
        '''
        :param locator:
        :return:
        '''
        locator = locate_with(*dst_locator).to_left_of({ref_locator[0]:ref_locator[1]})
        return locator

    def element_above(self,dst_locator:tuple,ref_locator:tuple)->WebElement:
        '''
        :param locator:
        :return:
        '''
        locator = locate_with(*dst_locator).above({ref_locator[0]:ref_locator[1]})
        return locator

    def element_below(self,dst_locator:tuple,ref_locator:tuple)->WebElement:
        '''
        :param locator:
        :return:
        '''
        locator = locate_with(*dst_locator).below({ref_locator[0]:ref_locator[1]})
        return locator

    def clear(self,locator:tuple):
        self.find_element(locator).clear()

    def input_text(self,locator:tuple,text:string):
        '''
        :param locator: locator
        :param text: string
        :return:
        '''
        self.clear(locator)
        self.find_element(locator).send_keys(text)

    def click(self,locator:tuple):
        self.find_element(locator).click()

    def move_to(self,locator:tuple):
        element = self.find_element(locator)
        ActionChains(self.driver) \
            .move_to_element(element) \
            .perform()



    def wait_until(self,expected_condition,locator:tuple=None,timeout=3,interval=0.5):
        wait = WebDriverWait(self.driver, timeout=timeout, poll_frequency=interval)
        if expected_condition == EC.alert_is_present:
            wait.until(expected_condition())
        else:
            wait.until(expected_condition(locator))
    def wait_until_element_present(self,locator:tuple,timeout=3,interval=0.5):
        self.wait_until(EC.presence_of_element_located,locator,timeout,interval)

    def wait_until_alert_present(self,timeout=3,interval=0.5):
        self.wait_until(EC.alert_is_present, timeout, interval)
    def wait_until_element_visibale(self,locator:tuple,timeout=3,interval=0.5):
        self.wait_until(EC.visibility_of_element_located, locator,timeout, interval)

    def wait(self,seconds):
        time.sleep(seconds)
    def switch_to_alert(self):
        self.alert = self.driver.switch_to.alert
    def alert_accept(self):
        self.switch_to_alert()
        self.alert.accept()
    def alert_dismiss(self):
        self.switch_to_alert()
        self.alert.dismiss()
    def get_alert_text(self):
        self.switch_to_alert()
        return self.alert.text
    def switch_to_iframe(self,locator):
        iframe =self.find_element(locator)
        self.driver.switch_to.frame(iframe)
    def switch_to_default(self):
        self.driver.switch_to.default_content()
    def get_title(self):
        return self.driver.title

    def get_url(self):
        return self.driver.current_url

    def get_link_text(self,locator):
        return self.find_element(locator).text

    def get_input_text(self,locator):
        return self.find_element(locator).text

    def get_text(self,locator):
        return self.find_element(locator).text

    def get_value(self,locator):
        return self.find_element(locator).get_property('value')